<?php

/**
 * JingYao-backend
 *
 * @link     https://gitee.com/wang-zhihui-release/jingyao-backend
 * @apiDocument https://gitee.com/wang-zhihui-release/jingyao-backend/wikis/
 */

namespace App\Services;

use App\Enums\AdminActionTypeEnum;
use App\Enums\EnableStatusEnum;
use App\Exceptions\ApiException;
use App\Format\AdminRoleFormat;
use App\Format\AdminUserFormat;
use App\Models\AdminAction;
use App\Models\AdminRole;
use App\Models\AdminRoleAction;
use App\Models\AdminUser;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;

class AdminAuthService
{
    public function getRoles()
    {
        return AdminRole::query()->get();
    }

    public function getActions()
    {
        return AdminAction::query()->select('id', 'action_desc', 'uuid')->get();
    }

    public function setActions(int $roleId, string $actionUuids)
    {
        /** @var null|AdminRole $role */
        $role = AdminRole::query()->find($roleId);
        if (! $role) {
            throw new ApiException('此角色不存在', 1);
        }
        $saveActionIds = explode(',', $actionUuids);
        $actionCount = AdminAction::query()->whereIn('uuid', $saveActionIds)->count();
        if ($actionCount < count($saveActionIds)) {
            Log::error('妄图设置不存在的权限', [
                'action_uuids' => $actionUuids,
            ]);
            throw new ApiException('有不支持的权限', 1);
        }
        foreach ($saveActionIds as $saveActionId) {
            $exist = AdminRoleAction::query()->where('admin_role_id', $roleId)
                ->where('admin_action_uuid', $saveActionId)->exists();
            if (! $exist) {
                AdminRoleAction::query()->create([
                    'admin_role_id' => $roleId,
                    'admin_action_uuid' => $saveActionId,
                ]);
            }
        }
        $currActionIds = AdminRoleAction::query()->where('admin_role_id', $roleId)
            ->select('admin_action_uuid')->pluck('admin_action_uuid')->toArray();

        $needDeleteAuthActions = array_values(array_diff($currActionIds, $saveActionIds));
        if (! empty($needDeleteAuthActions)) {
            AdminRoleAction::query()->where('admin_role_id', $roleId)
                ->whereIn('admin_action_uuid', $needDeleteAuthActions)->delete();
        }
        return true;
    }

    /**
     * @throws ApiException
     * @return Collection
     */
    public function getUserRoleActions(int $userId)
    {
        /** @var AdminUser $user */
        $user = AdminUser::query()->select('admin_role_id')->find($userId);
        if (empty($user)) {
            throw new ApiException('用户不存在', 1);
        }
        if ($user->admin_role_id == 0) {
            throw new ApiException('用户不是管理员', 1);
        }
        $actionIds = AdminRoleAction::query()->where('admin_role_id', $user->admin_role_id)->get()
            ->pluck('admin_action_uuid')->toArray();

        return AdminAction::query()->whereIn('uuid', $actionIds)->select('id', 'action_desc', 'uuid')->get();
    }

    public function checkAuth(int $userId, $actionName)
    {
        /** @var AdminUser $user */
        $user = AdminUser::query()->select('admin_role_id')->find($userId);
        if (empty($user)) {
            throw new ApiException('用户不存在', 1);
        }
        if ($user->admin_role_id == 0) {
            throw new ApiException('用户不是管理员', 1);
        }

        // 权限对超管无效
        if ($user->admin_role_id == 1) {
            return true;
        }

        // 文章类型统一放过去, 在具体的 method 里判断
        if (strpos($actionName, 'ArticleController')) {
            return true;
        }

        // 文章类型的 action_name 会重复 这样取第一条是不对的
        /** @var null|AdminAction $action */
        $action = AdminAction::query()->where('action_name', $actionName)->first();

        if (empty($action)) {
            Log::error('此接口没有登记权限', [
                'action_name' => $actionName,
            ]);
            throw new ApiException('此接口没有登记权限', 1);
        }

        return AdminRoleAction::query()->where('admin_role_id', $user->admin_role_id)
            ->where('admin_action_uuid', $action->uuid)->exists();
    }

    public function getAdminUsers(int $page, int $pageSize, array $search)
    {
        $builder = AdminUser::query()
            ->with([
                'role',
                'assessLog' => function ($query) {
                    /* @var Builder $query */
                    $query->where('assess_time', '>=', strtotime(date('Y') . '-01-01'));
                    $query->where('assess_time', '<=', strtotime(date('Y') . '-12-31'));
                },
            ])
            ->select('name', 'phone', 'admin_role_id', 'avatar', 'login_status', 'id')
            ->where('admin_role_id', '>', 0);
        if (isset($search['name'])) {
            $builder->where('name', $search['name']);
            adminLog(new AdminUser(), AdminActionTypeEnum::SELECT, '查询管理员');
        }

        $count = $builder->count();

        $list = $builder->skip(($page - 1) * $pageSize)->take($pageSize)->get();

        return [
            'count' => $count,
            'page' => $page,
            'page_size' => $pageSize,
            'list' => $list,
        ];
    }

    public function disabledAdminUser(int $adminUserId)
    {
        /** @var null|AdminUser $adminUser */
        $adminUser = AdminUser::query()->find($adminUserId);
        if (empty($adminUser)) {
            throw new ApiException('管理员不存在', 1);
        }
        $adminUser->login_status = EnableStatusEnum::DISABLE;
        $adminUser->save();
        adminLog($adminUser, AdminActionTypeEnum::UPDATE, '封禁管理员');
        return true;
    }

    public function enableAdminUser(int $adminUserId)
    {
        /** @var null|AdminUser $adminUser */
        $adminUser = AdminUser::query()->find($adminUserId);
        if (empty($adminUser)) {
            throw new ApiException('管理员不存在', 1);
        }
        $adminUser->login_status = EnableStatusEnum::ENABLE;
        $adminUser->save();
        adminLog($adminUser, AdminActionTypeEnum::UPDATE, '解禁管理员');
        return true;
    }

    public function createAdminRole(AdminRoleFormat $adminRoleFormat)
    {
        if (AdminRole::query()->where('name', $adminRoleFormat->getName())->exists()) {
            throw new ApiException(sprintf('角色 %s 已存在', $adminRoleFormat->getName()), 1);
        }
        /** @var AdminRole $adminRole */
        $adminRole = AdminRole::query()->create($adminRoleFormat->toArrayNotNull());
        $defaultActions = config('default_role');
        $uuids = array_column($defaultActions, 'uuid');
        $uuidString = implode(',', $uuids);
        $this->setActions($adminRole->id, $uuidString);
        adminLog(new AdminRole(), AdminActionTypeEnum::CREATE, '创建管理员角色');
        return true;
    }

    public function updateAdminRole(AdminRoleFormat $adminRoleFormat)
    {
        $id = $adminRoleFormat->getId();
        if (empty($id)) {
            throw new ApiException('缺少参数', 1);
        }
        $adminRole = AdminRole::query()->find($id);
        $adminRoleFormat->setId(null);
        $adminRole->update($adminRoleFormat->toArrayNotNull());
        return true;
    }

    public function updateAdminUser(AdminUserFormat $adminUserFormat)
    {
        $id = $adminUserFormat->getId();
        if (empty($id)) {
            throw new ApiException('缺少参数', 1);
        }
        if (! empty($adminUserFormat->getPassword())) {
            $adminUserFormat->setPassword(md5($adminUserFormat->getPassword()));
        }
        if (! empty($adminUserFormat->getAdminRoleId())) {
            if (! $this->checkVaildAdminRoleId($adminUserFormat->getAdminRoleId())) {
                throw new ApiException('角色非法', 1);
            }
        }
        $adminUser = AdminUser::query()->find($id);
        $adminUserFormat->setId(null);
        $adminUser->update($adminUserFormat->toArrayNotNull());
        return true;
    }

    public function getRoleActions(int $roleId)
    {
        return AdminRoleAction::query()->where('admin_role_id', $roleId)->get();
    }

    public function setUserRole(int $userId, int $roleId)
    {
        AdminUser::query()->where('id', $userId)->update([
            'admin_role_id' => $roleId,
        ]);
        return true;
    }

    public function checkSuperAdmin(int $userId)
    {
        return AdminUser::query()->where('id', $userId)
            ->where('admin_role_id', 1)
            ->exists();
    }

    private function checkVaildAdminRoleId(int $adminRoleId)
    {
        return AdminRole::query()->where('id', $adminRoleId)->exists();
    }
}
